/*
 * Copyright (c) 2012 Jonathan Tyers
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package uk.org.uplink.guicemodulescanner;

import static java.util.Arrays.asList;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import org.junit.Test;

import uk.org.uplink.guicemodulescanner.configuration.Configuration;
import uk.org.uplink.guicemodulescanner.integrationtest.pkg1.Module1;
import uk.org.uplink.guicemodulescanner.integrationtest.pkg1.pkg1a.Module1a;

import com.google.inject.Module;

/**
 * Integration test for {@link ModuleScanner} that exercises basic module scanning functionality.
 * 
 * @author jonny
 */
public class ModuleScannerTest {
	private static void assertModuleClasses(final Set<Module> modules, final Class<?>... classes) {
		List<Class<?>> classesList = asList(classes);
		Set<Class<?>> wantedClasses = new LinkedHashSet<Class<?>>(classesList);

		Set<Class<?>> actualClasses = new LinkedHashSet<Class<?>>();
		for (Module module : modules) {
			actualClasses.add(module.getClass());
		}

		if (actualClasses.size() != wantedClasses.size() ||
				!actualClasses.containsAll(wantedClasses)) {
			fail("Wanted modules: " + classesList + "\nbut got: " + actualClasses);
		}
	}

	@Test
	public void shouldFindAllModulesIfNoIncludePackagesAreGiven() {
		// Given
		ModuleScanner moduleScanner = new ModuleScanner();

		// When
		Set<Module> modules = moduleScanner.scanForModules();

		// Then
		assertModuleClasses(modules, Module1.class, Module1a.class);
	}

	@Test
	public void shouldOnlyFindModulesInIncludedPackagesIfIncludePackagesAreGiven() {
		// Given
		Configuration configuration = new Configuration().includePackages("uk.org.uplink.guicemodulescanner.integrationtest.pkg1.pkg1a");
		ModuleScanner moduleScanner = new ModuleScanner(configuration);

		// When
		Set<Module> modules = moduleScanner.scanForModules();

		// Then
		assertModuleClasses(modules, Module1a.class);
	}

	@Test
	public void shouldFindNoModulesIfAllPackagesAreExcluded() {
		// Given
		Configuration configuration = new Configuration().excludePackages("uk.org.uplink.guicemodulescanner.integrationtest.pkg1");
		ModuleScanner moduleScanner = new ModuleScanner(configuration);

		// When
		Set<Module> modules = moduleScanner.scanForModules();

		// Then
		assertTrue(modules.isEmpty());
	}

	@Test
	public void shouldFindModulesInPackagesAndSubpackages() {
		// Given
		Configuration configuration = new Configuration().includePackages("uk.org.uplink.guicemodulescanner.integrationtest.pkg1");
		ModuleScanner moduleScanner = new ModuleScanner(configuration);

		// When
		Set<Module> modules = moduleScanner.scanForModules();

		// Then
		assertModuleClasses(modules, Module1.class, Module1a.class);
	}

	@Test
	public void shouldRespectPackageExcludesEvenIfWithinIncludedPackage() {
		// Given
		Configuration configuration = new Configuration()
		.includePackages("uk.org.uplink.guicemodulescanner.integrationtest.pkg1")
		.excludePackages("uk.org.uplink.guicemodulescanner.integrationtest.pkg1.pkg1a");
		ModuleScanner moduleScanner = new ModuleScanner(configuration);

		// When
		Set<Module> modules = moduleScanner.scanForModules();

		// Then
		assertModuleClasses(modules, Module1.class);
	}
}
